package com.uchedao.seller.ui.car.publish.vin.http;

import android.os.Message;

import com.google.gson.Gson;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public abstract class ModelHttpResponseHandler<T, E> extends AsyncHttpResponseHandler {
	protected static final int SUCCESS_MODEL_MESSAGE = 200;

	private Type mModelType;
	private Type mFailureModelType;

	public ModelHttpResponseHandler() {

	}

	public void setFailureModelType(Type failureModelType) {
		mFailureModelType = failureModelType;
	}

	public void setModelType(Type modelType) {
		mModelType = modelType;
	}

	private void getTEType() {
		Type genType = getClass().getGenericSuperclass();
		if (genType != null && genType instanceof ParameterizedType) {
			Type[] args = ((ParameterizedType) genType).getActualTypeArguments();
			if (args != null) {
				if (args.length > 0) {
					mModelType = args[0];
				}
				if (args.length == 2) {
					mFailureModelType = args[1];
				}
			}
		}
	}

	//
	// Callbacks to be overridden, typically anonymously
	//

	/**
	 * Fired when a request returns successfully and contains a json object at
	 * the base of the response string. Override to handle in your own code.
	 * 
	 * @param response
	 *            the parsed json object found in the server response (if any)
	 */
	public void onSuccess(T response) {
	}

	/**
	 * Fired when a request returns successfully and contains a json array at
	 * the base of the response string. Override to handle in your own code.
	 * 
	 * @param
	 *            the parsed json array found in the server response (if any)
	 */
	public void onFailure(HttpFailureException e) {
//		L.e("onFailure "+e.toString());
	}

	public void onFailure(HttpFailureException e, E errorResponse) {
//		L.e("onFailure "+e.toString() +" response "+errorResponse);
	}

	//
	// Pre-processing of messages (executes in background threadpool thread)
	//

	@Override
	protected void sendSuccessMessage(String responseBody) {
		try {
			sendMessage(obtainMessage(SUCCESS_MODEL_MESSAGE, responseBody));
		} catch (Exception e) {
			sendFailureMessage(new HttpFailureException(e), responseBody);
		}
	}

	protected void sendSuccessMessage(int statusCode, String responseBody) {
		sendMessage(obtainMessage(SUCCESS_MODEL_MESSAGE, responseBody));
	}

	//
	// Pre-processing of messages (in original calling thread, typically the UI
	// thread)
	//

	@Override
	protected void handleMessage(Message msg) {
		switch (msg.what) {
		case SUCCESS_MODEL_MESSAGE:
			handleSuccessModelMessage(msg.obj);
			break;
		default:
			super.handleMessage(msg);
		}
	}

	protected void handleSuccessModelMessage(Object objectResponse) {
		T modelResponse = parseResponse(objectResponse);
		onSuccess(modelResponse);
	}

	private T parseResponse(Object responseBody) {
		String modelBody = processModelBody((String) responseBody);
		if (modelBody == null) {
			return null;
		}
		if (mModelType == null) {
			getTEType();
		}
		return modelFromJson(modelBody, mModelType);
	}

	private E parseFailureResponse(Object responseBody) {
		String failureBody = processFailureModelBody((String) responseBody);
		if (failureBody == null) {
			return null;
		}
		if (mFailureModelType == null) {
			getTEType();
		}
		return failureModelFromJson(failureBody, mFailureModelType);
	}

	protected String processModelBody(String responseBody) {
		return responseBody;
	}

	protected String processFailureModelBody(String responseBody) {
		return responseBody;
	}

	protected E failureModelFromJson(String json, Type type) {
		return new Gson().fromJson(json, type);
	}

	protected T modelFromJson(String json, Type type) {
		return new Gson().fromJson(json, type);
	}

	@Override
	protected void handleFailureMessage(HttpFailureException e, String responseBody) {
		if (responseBody != null)
			try {
				E failureResponse = parseFailureResponse(responseBody);
				onFailure(e, failureResponse);
			} catch (Exception ex) {
//				L.e("handleFailureMessage "+ex.toString());
				onFailure(e, responseBody);
			}
		else {
//			L.e("handleFailureMessage responseBody==null");
			onFailure(e, "");
		}
	}
}
